/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package am.aua.renju.databaseaccess;

import am.aua.renju.databaseaccess.util.GameState;
import am.aua.renju.entity.Game;
import am.aua.renju.entity.Player;
import java.util.List;
import javax.persistence.*;

/**
 *
 * @author ara
 */
public class GameOperations implements IGameOperations {

    private static GameOperations instance;

    private EntityManagerFactory emf;

    public static IGameOperations getInstance() {
        if (instance == null) {
            instance = new GameOperations();
        }
        return instance;
    }

    private GameOperations() {
        emf = Persistence.createEntityManagerFactory("RenjuDPU");
    }

    @Override
    public void createGame(Game game) {
        EntityManager em = emf.createEntityManager();
        EntityTransaction et = em.getTransaction();
        et.begin();
        em.persist(game);
        et.commit();
        em.close();
    }

    @Override
    public List<Game> getPlayedGames(int userId) {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Game> query = em.createQuery("SELECT g FROM Game g WHERE g.player1Id=:userId AND (g.state=:state1 OR g.state='player2_won')", Game.class).
                setParameter("userId", userId).setParameter("state1", GameState.PLAYER1_WON).setParameter("state2", GameState.PLAYER2_WON);
        List<Game> result = query.getResultList();
        em.close();
        return result;
    }

    @Override
    public Game getGameById(int id) {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Game> query = em.createNamedQuery("Game.findById", Game.class).setParameter("id", id);
        Game result = query.getSingleResult();
        em.close();
        return result;
    }

    @Override
    public List<Game> getGames(Player player1Id) {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Game> query = em.createQuery("SELECT g FROM Game g WHERE g.player1Id=:player1Id", Game.class).
                setParameter("player1Id", player1Id);
        List<Game> result = query.getResultList();
        em.close();
        return result;
    }

    @Override
    public List<Game> getWaitGames() {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Game> query = em.createQuery("SELECT g FROM Game g WHERE g.state=:state", Game.class).
                setParameter("state", GameState.WAIT.toString());
        List<Game> result = query.getResultList();
        em.close();
        return result;
    }

    @Override
    public Game getWaitGame(Player player1, int time, short startRules) {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Game> query = em.createQuery("SELECT g FROM Game g WHERE g.state=:state AND g.player1Id=:player1Id AND g.time=:time AND g.startRules=:startRules", Game.class).
                setParameter("state", GameState.WAIT.toString()).setParameter("player1Id", player1).setParameter("time", time).setParameter("startRules", startRules);
        Game result;
        try {
            result = query.getSingleResult();
        } catch (NoResultException ex) {
            return null;
        } finally {
            em.close();
        }
        return result;
    }

    @Override
    public Game getWaitGame(Player player1, short startRules) {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Game> query = em.createQuery("SELECT g FROM Game g WHERE g.state=:state AND g.player1Id=:player1Id AND g.time IS NULL AND g.startRules=:startRules", Game.class).
                setParameter("state", GameState.WAIT.toString()).setParameter("player1Id", player1).setParameter("startRules", startRules);
        Game result;
        try {
            result = query.getSingleResult();
        } catch (NoResultException ex) {
            return null;
        } finally {
            em.close();
        }
        return result;
    }

    @Override
    public Game getPlayGame(Player player) {
        EntityManager em = emf.createEntityManager();
        TypedQuery<Game> query = em.createQuery("SELECT g FROM Game g WHERE g.state=:state AND (g.player1Id=:player OR g.player2Id=:player)", Game.class).
                setParameter("state", GameState.PLAY.toString()).setParameter("player", player);
        Game result;
        try {
            result = query.getSingleResult();
        } catch (NoResultException ex) {
            return null;
        } finally {
            em.close();
        }
        return result;
    }

    @Override
    public void updateGameToJoin(int gameId, Player player2, short isPlayer1White) {
        EntityManager em = emf.createEntityManager();
        Query query = em.createQuery("UPDATE Game g SET g.player2Id=:player2Id ,g.state=:state, g.isPlayer1White=:isPlayer1White  WHERE g.id=:gameId").
                setParameter("player2Id", player2).setParameter("state", GameState.PLAY.toString()).setParameter("gameId", gameId).setParameter("isPlayer1White", isPlayer1White);
        EntityTransaction et = em.getTransaction();
        et.begin();
        query.executeUpdate();
        et.commit();
        em.close();
    }

    @Override
    public void updateGameState(int id, GameState state) {
        EntityManager em = emf.createEntityManager();
        Query query = em.createQuery("UPDATE Game g SET g.state=:state WHERE g.id=:id").
                setParameter("state", state.toString()).setParameter("id", id);
        EntityTransaction et = em.getTransaction();
        et.begin();
        query.executeUpdate();
        et.commit();
        em.close();
    }

    @Override
    public void deleteWaitGames(Player user) {
        EntityManager em = emf.createEntityManager();
        Query query = em.createQuery("Delete FROM Game g WHERE g.player1Id=:user AND g.state=:state").
                setParameter("user", user).setParameter("state", GameState.WAIT.toString());
        EntityTransaction et = em.getTransaction();
        et.begin();
        query.executeUpdate();
        et.commit();
        em.close();
    }

    @Override
    public void deleteGames(Player user) {
        EntityManager em = emf.createEntityManager();
        Query query = em.createQuery("DELETE FROM Game g WHERE g.player1Id=:user").
                setParameter("user", user);
        EntityTransaction et = em.getTransaction();
        et.begin();
        query.executeUpdate();
        et.commit();
        em.close();
    }

    @Override
    public void close() {
        if (emf.isOpen()) {
            emf.close();
        }
        Operations.instance = null;
    }

    @Override
    public void deleteGame(Player user, int time, short startRules) {
        EntityManager em = emf.createEntityManager();
        EntityTransaction et = em.getTransaction();
        Query query;
        if (time != 0) {
            query = em.createQuery("DELETE FROM Game g WHERE g.player1Id=:user AND g.time=:time AND g.startRules=:startRules").
                    setParameter("user", user).setParameter("time", time).setParameter("startRules", startRules);
        } else {
            query = em.createQuery("DELETE FROM Game g WHERE g.player1Id=:user AND g.startRules=:startRules").
                    setParameter("user", user).setParameter("startRules", startRules);
        }
        et.begin();
        query.executeUpdate();
        et.commit();
        em.close();
    }
}
